﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using DevComponents.AdvTree;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using PlanningGIS.ArcGIS;
using PlanningGIS.Util.Log;

namespace PlanningGIS.Framework.Controls
{
    /// <summary>
    /// 行政区划树控件
    /// </summary>
    public partial class RegionTree : AdvTree
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public RegionTree()
        {
            InitializeComponent();
            this.DragDropEnabled = false;
            this.DragDropNodeCopyEnabled = false;
            if (!this.DesignMode) //运行时才执行
                AddNodes();
            IsToMap = true;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="container"></param>
        public RegionTree(IContainer container)
            : this()
        {
            container.Add(this);
            InitializeComponent();
        }

        /// <summary>
        /// 地图关联对象
        /// </summary>
        private IHookHelper _HookHelper = null;

        /// <summary>
        /// 地图关联对象
        /// </summary>
        public object Hook
        {
            set
            {
                try
                {
                    _HookHelper = new HookHelper();
                    _HookHelper.Hook = value;
                }
                catch 
                {
                    _HookHelper = null;
                }
            }
        }

        /// <summary>
        /// 获取或设置是否将选中的对象添加到地图中
        /// </summary>
        public bool IsToMap { get; set; }

        /// <summary>
        /// 添加到地图中的对象
        /// </summary>
        public List<IElement> DrawElements { get; private set; }
        
        /// <summary>
        /// 选择的行政区
        /// </summary>
        public List<GeoRegion> SelectedRegions { get; set; }

        /// <summary>
        /// 选择的空间对象，合并为一个对象
        /// </summary>
        public IGeometry SelectedGeometry { get { return GetSelectGeometry(); } }
        
        /// <summary>
        /// 添加行政区到树节点中
        /// </summary>
        private void AddNodes()
        {
            this.Nodes.Clear();
            GC.Collect();
            if (RegionHelper.RegionRoot == null) return;
            Node nd = new Node();
            nd.Text = RegionHelper.RegionRoot.Name;
            nd.Name = RegionHelper.RegionRoot.Code;
            nd.Tag = RegionHelper.RegionRoot;
            nd.CheckBoxVisible = true;
            try
            {
                if (RegionHelper.RegionImages != null && RegionHelper.RegionImages.Count > 0)
                {
                    if (RegionHelper.RegionImages.ContainsKey(RegionHelper.RegionRoot.Code.Length))
                        nd.Image = RegionHelper.RegionImages[RegionHelper.RegionRoot.Code.Length];
                }
            }
            catch
            {
                
            }
            try
            {
                AddNodes(nd, RegionHelper.RegionRoot.Nodes);
                Nodes.Add(nd);
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorText(ex.Message);
            }
            this.ExpandAll();
        }

        /// <summary>
        /// 添加行政区到树节点中
        /// </summary>
        /// <param name="node">要添加到的树节点</param>
        /// <param name="regions">要添加的行政区</param>
        private void AddNodes(Node node, List<RegionNode> regions)
        {
            foreach (RegionNode rn in regions)
            {
                Node nd = new Node();
                nd.Text = rn.Name;
                nd.Name = rn.Code;
                nd.Tag = rn;
                nd.CheckBoxVisible = true;
                try
                {
                    if (RegionHelper.RegionImages != null && RegionHelper.RegionImages.Count > 0)
                    {
                        if (RegionHelper.RegionImages.ContainsKey(rn.Code.Length))
                            nd.Image = RegionHelper.RegionImages[rn.Code.Length];
                    }
                }
                catch
                {

                }
                try
                {
                    AddNodes(nd, rn.Nodes);
                    node.Nodes.Add(nd);
                }
                catch (Exception ex)
                {
                    LogHelper.WriteErrorText(ex.Message);
                }
            }
            GC.Collect();
        }

        /// <summary>
        /// 根据空间对象，选择所需要的行政区
        /// </summary>
        /// <param name="geometry">空间对象</param>
        /// <param name="shift">0没有按下shift键</param>
        public void SelectRegion(IGeometry geometry, int shift)
        {
            this.SelectedNode = null;
            if (SelectedRegions == null) SelectedRegions = new List<GeoRegion>();
            if (geometry == null || geometry.IsEmpty) return;
            if (RegionHelper.LastFeatureClass == null) return;
            if (shift == 0)//未点Shift键
            {
                ClearNodeCheck(this.Nodes);
                Clear();
            }
            ISpatialReference spref = (RegionHelper.LastFeatureClass as IGeoDataset).SpatialReference;
            if (geometry is IPoint) geometry = (geometry as IPoint).ToCircle(0.05, spref);
            else
            {
                if (geometry is IEnvelope) geometry = ((IEnvelope)geometry).ToPolygon();
                if (geometry == null || geometry.IsEmpty) return;
                //往内缩以免把边上相邻的行政区选中了
                IGeometry geo = GeometryHelper.GetBuffer(geometry, -0.04, spref);
                if (geo != null && !geo.IsEmpty) geometry = geo;
            }
            if (geometry == null || geometry.IsEmpty) return;
            ISpatialFilter spatialFilter = new SpatialFilter();
            spatialFilter.Geometry = geometry;
            spatialFilter.GeometryField = RegionHelper.LastFeatureClass.ShapeFieldName;
            spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
            try
            {
                IFeatureCursor featCursor = RegionHelper.LastFeatureClass.Search(spatialFilter, false);
                int idxCD = RegionHelper.LastFeatureClass.Fields.FindField(RegionHelper.F_CODE);
                int idxNM = RegionHelper.LastFeatureClass.Fields.FindField(RegionHelper.F_NAME);
                IFeature feature = null;
                while ((feature = featCursor.NextFeature()) != null)
                {
                    string code = feature.get_Value(idxCD).ToString();
                    string name = feature.get_Value(idxNM).ToString();
                    Node[] nodes = this.Nodes.Find(code, true);
                    if (nodes.Length > 0)
                    {
                        Node node = nodes[0];
                        node.Checked = true;
                        SetParentChange(node);
                    }
                    AddToMap(feature.Shape, code);
                    if (SelectedRegions != null && !SelectedRegions.Exists(t => t.Code == code))
                        SelectedRegions.Add(new GeoRegion() { Code = code, Name = name, Geometry = feature.Shape });
                }
                if (_HookHelper != null && _HookHelper.ActiveView != null && IsToMap)
                    _HookHelper.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, _HookHelper.ActiveView.Extent);
            }
            catch
            {

            }
        }

        /// <summary>
        /// 根据行政区代码，选择行政区
        /// </summary>
        public void SelectByCodes(List<string> codes)
        {
            if (SelectedRegions == null) SelectedRegions = new List<GeoRegion>();
            this.SelectedNode = null;
            if (codes == null || codes.Count == 0) return;
            ClearNodeCheck(this.Nodes);
            Clear();
            try
            {
                foreach (string code in codes)
                {
                    Node[] nodes = this.Nodes.Find(code, true);
                    if (nodes.Length > 0)
                    {
                        Node node = nodes[0];
                        node.Checked = true;
                        SetParentChange(node);
                        if (node.Tag != null && node.Tag is RegionNode)
                        {
                            RegionNode rnd = (RegionNode)node.Tag;
                            if (rnd != null)
                            {
                                IFeature feat = RegionHelper.RegionList[rnd.LayerName].GetFeature(rnd.OID);
                                if(feat!=null && feat.Shape!=null && !feat.Shape.IsEmpty)
                                {
                                    AddToMap(feat.Shape, code);
                                    if (SelectedRegions != null && !SelectedRegions.Exists(t => t.Code == code))
                                        SelectedRegions.Add(new GeoRegion() { Code = code, Name = node.Text, Geometry = feat.Shape });
                                }                                
                            }
                        }
                    }
                }
                if (_HookHelper != null && _HookHelper.ActiveView != null && IsToMap)
                    _HookHelper.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, _HookHelper.ActiveView.Extent);
            }
            catch
            {

            }
        }

        /// <summary>
        /// 选择节点
        /// </summary>
        /// <param name="e"></param>
        protected override void OnAfterCheck(AdvTreeCellEventArgs e)
        {
            if (SelectedRegions == null) SelectedRegions = new List<GeoRegion>();
            base.OnAfterCheck(e);
            if (e.Action == eTreeAction.Mouse)
            {
                SetChildChange(this.SelectedNode);
                SetParentChange(this.SelectedNode);
                if (_HookHelper == null || !IsToMap) return;
                _HookHelper.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics| esriViewDrawPhase.esriViewGeography, null, _HookHelper.ActiveView.Extent);
            }
        }

        /// <summary>
        /// 获取选择的空间对象
        /// </summary>
        /// <returns></returns>
        public IGeometry GetSelectGeometry()
        {
            if (SelectedRegions == null || SelectedRegions.Count == 0) return null;
            var v = from p in SelectedRegions
                    select p.Geometry;
            return GeometryHelper.Union(v.ToList());
        }

        /// <summary>
        /// 更改父节点状态（支持勾、不勾和半勾）
        /// </summary>
        /// <param name="node"></param>
        private void SetParentChange(Node node)
        {
            if (node.Parent == null) return;
            bool hasChecked = false;
            bool hasNoCheced = false;
            foreach (Node nd in node.Parent.Nodes)
            {
                if (nd.Checked || nd.CheckState == CheckState.Indeterminate)
                    hasChecked = true;
                else
                    hasNoCheced = true;
            }
            if (hasChecked && hasNoCheced)
                node.Parent.CheckState = CheckState.Indeterminate;
            else if (!hasChecked)
                node.Parent.CheckState = CheckState.Unchecked;
            else
                node.Parent.CheckState = CheckState.Checked;
            SetParentChange(node.Parent);
        }

        /// <summary>
        /// 更新子节点状态
        /// </summary>
        /// <param name="node"></param>
        private void SetChildChange(Node node)
        {
            if (node.Nodes.Count == 0)
            {
                if (SelectedRegions != null && !SelectedRegions.Exists(t => t.Code == node.Name) && node.Checked)
                {
                    IGeometry geo = null;
                    if(node.Tag is RegionNode)
                    {
                        RegionNode rnd = (RegionNode)node.Tag;
                        geo = RegionHelper.GetRegionGeometry(rnd.OID, rnd.LayerName);
                    }
                    SelectedRegions.Add(new GeoRegion() { Code = node.Name, Name = node.Text, Geometry = geo });
                    AddToMap(geo, node.Name);
                }
                else if (SelectedRegions != null && SelectedRegions.Exists(t => t.Code == node.Name) && !node.Checked)
                {
                    SelectedRegions.RemoveAll(t => t.Code == node.Name);
                    RemoveToMap(node.Name);
                }                    
                return;
            }
                
            foreach (Node nd in node.Nodes)
            {
                nd.Checked = node.Checked;
                SetChildChange(nd);
            }
        }
        
        /// <summary>
        /// 将选中的对象添加的地图中
        /// </summary>
        /// <param name="geometry"></param>
        /// <param name="code"></param>
        private void AddToMap(IGeometry geometry,string code)
        {
            if (_HookHelper == null || !IsToMap) return;
            if (geometry == null || geometry.IsEmpty) return;
            if (DrawElements == null) DrawElements = new List<IElement>();
            if (DrawElements.Count > 0)
            {
               int cnt= DrawElements.Count(t => (t as IElementProperties3).Name.Equals(code));
               if (cnt > 0) return;
            }
            IRgbColor rgbColor = new RgbColor();
            rgbColor.Red = 255;
            rgbColor.Green = 0;
            rgbColor.Blue = 0;
            IElement ele = ElementHelper.AddPolygon(geometry as IPolygon, _HookHelper.ActiveView, rgbColor);
            (ele as IElementProperties3).Name = code;
            DrawElements.Add(ele);
        }

        /// <summary>
        /// 将指定的对象从地图中移除
        /// </summary>
        /// <param name="code"></param>
        private void RemoveToMap(string code)
        {
            if (SelectedRegions != null) SelectedRegions.RemoveAll(t => t.Code == code); 
            if (_HookHelper == null || !IsToMap) return;
            if (DrawElements == null) DrawElements = new List<IElement>();
            if (DrawElements.Count == 0) return;
            IElement ele = DrawElements.FirstOrDefault(t => (t as IElementProperties3).Name.Equals(code));
            if (ele == null || ele.Geometry == null) return;
            RemoveElement(ele);
            DrawElements.Remove(ele);
        }

        /// <summary>
        /// 清除地图上绘制的对象
        /// </summary>
        public void Clear()
        {
            if (SelectedRegions != null) SelectedRegions.Clear();
            if (_HookHelper == null) return;
            if (DrawElements == null || DrawElements.Count == 0) return;
            foreach (IElement itm in DrawElements)
            {
                RemoveElement(itm);
            }
            DrawElements.Clear();
            DrawElements = new List<IElement>();
            _HookHelper.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics | esriViewDrawPhase.esriViewGeography, null, _HookHelper.ActiveView.Extent);
        }

        /// <summary>
        /// 设置根节点为选中状态
        /// </summary>
        public void SetRootChecked()
        {
            if (this.Nodes.Count == 0) return;
            this.Nodes[0].Checked = true;
            SetChildChange(this.Nodes[0]);
        }

        /// <summary>
        /// 移除指定的对象
        /// </summary>
        /// <param name="ele"></param>
        private void RemoveElement(IElement ele)
        {
            if (_HookHelper == null || !IsToMap) return;
            try
            {
                IEnumElement em = _HookHelper.ActiveView.GraphicsContainer.LocateElementsByEnvelope(ele.Geometry.Envelope);
                if (em.Next() != null)
                    _HookHelper.ActiveView.GraphicsContainer.DeleteElement(ele);
            }
            catch
            {

            }
        }

        /// <summary>
        /// 清除选中的对象，设置为不选中。包含子集
        /// </summary>
        /// <param name="nodes">要清除的对象</param>
        public void ClearNodeCheck(NodeCollection nodes)
        {
            foreach (Node node in nodes)
            {
                node.CheckState = CheckState.Unchecked;
                ClearNodeCheck(node.Nodes);
            }
        }

        /// <summary>
        /// 获取选择的行政区的代码
        /// </summary>
        /// <param name="onlyLast"></param>
        /// <returns></returns>
        public List<string> GetCheckedCodes(bool onlyLast = true)
        {
            List<string> codes = new List<string>();
            GetCheckedCodes(codes, Nodes, onlyLast);
            return codes;
        }

        /// <summary>
        /// 获取选择的节点
        /// </summary>
        /// <param name="codes"></param>
        /// <param name="nodes"></param>
        /// <param name="onlyLast"></param>
        private void GetCheckedCodes(List<string> codes, NodeCollection nodes, bool onlyLast = true)
        {
            foreach(Node nd in nodes)
            {
                if (nd.HasChildNodes && onlyLast) GetCheckedCodes(codes, nd.Nodes, onlyLast);
                else
                {
                    if (nd.Checked) codes.Add(nd.Name);
                }

            }
        }
    }
    
}
